<?php
/**
 * Created by PhpStorm.
 * Script Name: Bot.php
 * Create: 2023/2/10 10:47
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace plugin\wechat\app\tenant\controller;

use app\common\constant\Platform;
use app\common\service\Queue;
use app\common\service\Tenant as TenantService;
use plugin\wechat\app\service\Bot as BotService;
use plugin\wechat\app\model\Bot as BotM;
use plugin\wechat\app\service\BotSetting as SettingService;
use plugin\wechat\app\TenantController;
use Support\Request;

class Bot extends TenantController
{

    /**
     * @var string
     */
    private $tip;

    /**
     * 初始化
     */
    public function __construct()
    {
        parent::__construct();
        $this->model = new BotM();
        $this->tip = "<p>若选择扫码登陆，请先在服务器上完成框架设置。加载二维码需要几秒钟，请耐心等待。</p> 
<ul><li>西瓜框架的接口回调地址: ".request()->domain()."/app/wechat/bot/my</li>
<li>可爱猫的接口回调地址: ".request()->domain()."/app/wechat/bot/cat</li>
<!--<li>XBot框架的接口回调地址: ".request()->domain()."/app/wechat/bot/xbot</li>  
<li>vlw的接口回调地址: ".request()->domain()."/app/wechat/bot/vlw</li> 
<li>千寻的接口回调地址: ".request()->domain()."/app/wechat/bot/qianxun</li>-->
<li>详细接入教程：<i class='fa fa-hand-o-right'></i><a target='_blank' href='http://daoadmin.kuryun.com/home/guide/bot/id/74/v/1.x.html'>点击查看</a></li></ul>";
    }

    private function tabList(){
        return [
            'index' => ['title' => 'Hook机器人', 'href' => url('index')]
        ];
    }

    /**
     * 机器人
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function index()
    {
        if (request()->isPost()) {
            $post_data = input('post.');
            $where = [
                $this->tenantIdWhere(),
                ['protocol', '<>', BotService::PROTOCOL_WEB]
            ];
            !empty($post_data['search_key']) && $where[] = ['nickname|title|uuid', 'like', '%' . $post_data['search_key'] . '%'];
            $query = $this->model->where($where);
            $total = $query->count();
            if ($total) {
                $list = $query->page($post_data['page'], $post_data['limit'])
                    ->order('update_time', 'desc')
                    ->select();
            } else {
                $list = [];
            }
            return $this->success('success', '', ['total' => $total, 'list' => $list]);
        }

        $bot = session(CURRENT_WECHAT);
        $builder = new ListBuilder();
        $builder->setSearch([
            ['type' => 'text', 'name' => 'search_key', 'title' => '关键词', 'placeholder' => '名称|昵称|微信号']
        ])
            ->setTabNav($this->tabList(), 'index')
            ->setTip("当前操作机器人：" . ($bot ? $bot['title'] : '无'))
            ->addTopButton('addnew', ['text' => '扫码登录','title' => '扫码登录', 'href' => url('hookadd')])
            ->addTopButton('addnew', ['text' => '手动添加','title' => '手动添加'])
            ->addTableColumn(['title' => 'Wxid', 'field' => 'uin', 'minWidth' => 190])
            ->addTableColumn(['title' => '类型', 'field' => 'protocol', 'type' => 'enum', 'options' => BotService::protocols(), 'minWidth' => 90])
            ->addTableColumn(['title' => '备注名称', 'field' => 'title', 'minWidth' => 90])
            ->addTableColumn(['title' => '头像', 'field' => 'headimgurl', 'type' => 'picture','minWidth' => 100])
            ->addTableColumn(['title' => 'appKey', 'field' => 'app_key', 'minWidth' => 200])
            ->addTableColumn(['title' => '昵称', 'field' => 'nickname', 'minWidth' => 80])
            ->addTableColumn(['title' => '登录状态', 'field' => 'alive', 'type' => 'enum', 'options' => [0 => '离线', 1 => '在线'], 'minWidth' => 70])
            ->addTableColumn(['title' => '创建时间', 'field' => 'create_time', 'type' => 'datetime', 'minWidth' => 180])
            ->addTableColumn(['title' => '操作', 'minWidth' => 240, 'type' => 'toolbar'])
            ->addRightButton('self', ['text' => '操作', 'href' => url('index/switch', ['id' => '__data_id__', 'type' => Platform::WECHAT]),'class' => 'layui-btn layui-btn-xs layui-btn-warm', 'minWidth' => 120])
            ->addRightButton('edit')
            ->addRightButton('self', ['text' => '清空聊天记录', 'href' => url('cleanChatPost', ['id' => '__data_id__']), 'data-ajax' => 1, 'data-confirm' => 1])
            ->addRightButton('delete');

        return $builder->show();
    }

    /**
     * 快速获取app_key和url
     * @return array|mixed|\think\db\Query|\think\Model|null
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function getConfig(){
        $config = $this->model->where([
            $this->tenantIdWhere()
        ])->order(['alive' => 'desc', 'update_time' => 'desc'])
            ->field(['app_key', 'url'])->find();
        if(! $config){
            $config = SettingService::getSettings(TenantService::getCompanyId(), 'default');
        }else{
            $config = $config->toArray();
        }
        return empty($config) ? [] : $config;
    }

    /**
     * 手动新增机器人
     * @return mixed
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function add()
    {
        $data = array_merge([
            'login_code' => 0,
            'protocol' => BotService::PROTOCOL_MY,
            'app_key' => get_rand_char(32)
        ], $this->getConfig());

        // 使用FormBuilder快速建立表单页面
        $builder = new FormBuilder();
        $builder->setMetaTitle('新增机器人')
            ->setTip($this->tip)
            ->setPostUrl(url('savePost'))
            ->addFormItem('protocol', 'radio', '类型', '机器人类型', BotService::hooks())
            ->addFormItem('title', 'text', '备注名称', '30字内', [], 'required maxlength=30')
            ->addFormItem('uin', 'text', 'Wxid', '微信在机器人框架登陆后可获取', [], 'required maxlength=30')
            ->addFormItem('app_key', 'text', 'AppKey', '请保证当前appkey与机器人框架上的配置相同', [], 'required')
            ->addFormItem('url', 'text', '接口地址', '请从机器人框架上获取', [], 'required')
            ->addFormItem('login_code', 'radio', '扫码登录', '是否扫码登录', [0 => '否', 1 => '是'])
            ->setFormData($data);

        return $builder->show();
    }

    /**
     * 编辑机器人
     * @return mixed|\support\Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function edit()
    {
        $id = input('id', null);
        $data = BotService::getBot($id);

        if (!$data) {
            return $this->error('参数错误');
        }
        $data['login_code'] = 0;
        // 使用FormBuilder快速建立表单页面
        $builder = new FormBuilder();
        $builder->setMetaTitle('编辑机器人')
            ->setTip($this->tip)
            ->setPostUrl(url('savePost'))
            ->addFormItem('id', 'hidden', 'ID', 'ID')
            ->addFormItem('protocol', 'radio', '类型', '机器人类型', BotService::hooks())
            ->addFormItem('title', 'text', '备注名称', '30字内', [], 'required maxlength=30')
            ->addFormItem('uin', 'text', 'Wxid', '微信在机器人框架登陆后可获取', [], 'required maxlength=30')
            ->addFormItem('app_key', 'text', 'AppKey', '请保证当前appkey与机器人框架上的配置相同', [], 'required')
            ->addFormItem('url', 'text', '接口地址', '请从机器人框架上获取', [], 'required')
            ->addFormItem('login_code', 'radio', '扫码登录', '是否扫码登录', [0 => '否', 1 => '是'])
            ->addFormItem('uuid', 'text', 'client_id', 'xbot类型的必填')
            ->setFormData($data);

        return $builder->show();
    }

    /**
     * 保存信息
     * @param Request $request
     * @param string $jump_to
     * @param array $data
     * @return mixed|\support\Response
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function savePost(Request $request, $jump_to = "", $data = []){
        $post_data = input('post.');
        $post_data['company_id'] = TenantService::getCompanyId();
        $login_code = $post_data['login_code'];
        unset($post_data['login_code']);
        if (empty($post_data[$this->pk])) {
            $post_data['tenant_id'] = $this->tenantInfo('id');
            $res = $this->model->createOne($post_data);
        } else {
            $res = $this->model->update($post_data);
        }
        if ($res) {
            if($login_code){
                switch ($post_data['protocol']){
                    case  BotService::PROTOCOL_XBOT:
                        $action = 'reloginxbot';
                        break;
                    default:
                        $action = 'reloginmy';
                        break;
                }
                return $this->success('保存成功，请继续扫码登录', url($action, ['id' => $res['id']]));
            }
            $msg = '数据保存成功';
            try{
                $info = BotService::getRobotInfo($res);
                if(is_string($info)){
                    $msg .= "，但是绑定机器人错误：".$info;
                }else if(!empty($info)){
                    $this->model->update([
                        'id' => $res['id'],
                        'uin' => $info['wxid'],
                        'username' => $info['username'],
                        'nickname' => $info['nickname'],
                        'headimgurl' => $info['headimgurl'],
                        'alive' => 1
                    ]);
                    //同步好友任务
                    Queue::push([
                        'consumer' => ['\\plugin\\wechat\\app\\queue\\Bot', 'pullMembers'],
                        'bot' => $res,
                        'delay' => 3
                    ]);
                }else{
                    $msg .= '，但系统检测到您的机器人尚未登录';
                }
            }catch (\Exception $e){
                $msg = "请检查接口地址是否填写正确" . $e->getMessage();
            }
            return $this->success($msg, $jump_to);
        } else {
            return $this->error('数据保存出错!', '', ['token' => token()]);
        }
    }

    /**
     * 扫码添加
     * @return mixed|\support\Response
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function hookAdd()
    {
        if(request()->isPost()){
            $post_data = input('post.');
            cache(wechat_cache_key('botadd' . $this->tenantInfo('id')), $post_data);
            switch ($post_data['protocol']){
                case  BotService::PROTOCOL_XBOT:
                    $action = 'loginxbot';
                    break;
                default:
                    $action = 'loginmy';
                    break;
            }

            return $this->success('请打开微信扫码登录', url($action, input('post.')));
        }

        $data = array_merge([
            'protocol' => BotService::PROTOCOL_MY,
            'app_key' => get_rand_char(32)
        ], $this->getConfig());

        // 使用FormBuilder快速建立表单页面
        $builder = new FormBuilder();
        $builder->setMetaTitle('扫码登录机器人')
            ->setTip("微信二维码加载需要几秒钟，点击提交后请耐心等待！<br>app_key和url读取顺序：上个机器人 > 设置默认值 <br> 如果需要填写新的，请先在服务器上完成框架设置并获取APPKey和http调用地址")
            ->setPostUrl(url('hookAdd'))
            ->addFormItem('protocol', 'radio', '类型', '机器人类型', BotService::canScan())
            ->addFormItem('app_key', 'text', 'AppKey', '请保证当前appkey与机器人框架上的配置相同', [], 'required')
            ->addFormItem('url', 'text', '接口地址', '请从机器人框架上获取', [], 'required')
            ->setFormData($data);
        return $builder->show();
    }

    /**
     * My扫码登录
     * @return mixed|\support\Response
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function loginMy(){
        $data = cache(wechat_cache_key('botadd' . $this->tenantInfo('id')));
        $jump = $data['jump'] ?? '';
        if (!$data) {
            $this->error('参数错误');
        }
        $data['uuid'] = '';
        $bot_client = BotService::getRobotClient($data);
        if(request()->isPost()){
            sleep(2);
            $return = $bot_client->getRobotList();
            if($return['code'] && !empty($return['data'])){
                foreach ($return['data'] as $v){
                    if($bot = BotService::getBotByUin(['uin' => $v['wxid']])){
                        $data = $this->model->update([
                            'id' => $bot['id'],
                            'username' => $v['username'],
                            'nickname' => $v['nickname'],
                            'headimgurl' => $v['headimgurl'],
                            'alive' => 1
                        ]);
                    }else{
                        $data = $this->model->createOne([
                            'uin' => $v['wxid'],
                            'company_id' => TenantService::getCompanyId(),
                            'tenant_id' => $this->tenantInfo('id'),
                            'title' => $v['nickname'],
                            'username' => $v['username'],
                            'app_key' => $data['app_key'],
                            'nickname' => $v['nickname'],
                            'headimgurl' => $v['headimgurl'],
                            'protocol' => $data['protocol'],
                            'url' => $data['url'],
                            'alive' => 1
                        ]);
                    }
                    //同步好友任务
                    Queue::push([
                        'consumer' => ['\\plugin\\wechat\\app\\queue\\Bot', 'pullMembers'],
                        'bot' => $data,
                        'delay' => 3
                    ]);
                }

                return $this->success('登录成功',$jump);
            }else{
                return $this->error('登录失败：' . $bot_client->getError());
            }
        }
        //退掉遗留的弹框
        // $bot_client->exitLoginCode();
        $res = $bot_client->getLoginCode();
        // Log::write("获取微信二维码：".json_encode($res));
        if($res['code'] == 0){
            return $this->error($res['errmsg']);
        }
        $data['code'] = base64_to_pic($res['data']);
        return $this->show($data);
    }

    /**
     * 编辑情况下的扫码登录
     * @return mixed
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function reLoginMy(){
        $id = input('id', null);
        $data = BotService::getBot($id);

        if (!$data) {
            return $this->error('参数错误');
        }
        $bot_client = BotService::getRobotClient($data);
        if(request()->isPost()){
            if($data['alive']){
                //获取机器人信息
                $info = BotService::getRobotInfo($data);
                if(!empty($info) && !is_string($info)){
                    $this->model->update([
                        'id' => $data['id'],
                        'username' => $info['username'],
                        'nickname' => $info['nickname'],
                        'headimgurl' => $info['headimgurl']
                    ]);
                }

                //同步好友任务
                Queue::push([
                    'consumer' => ['\\plugin\\wechat\\app\\queue\\Bot', 'pullMembers'],
                    'bot' => $data,
                    'delay' => 3
                ]);
                return $this->success('登录成功');
            }
        }

        $res = $bot_client->getLoginCode();
        if($res['code'] == 0){
            return $this->error($res['errmsg']);
        }

        $data['code'] = base64_to_pic($res['data']);
        return $this->show($data);
    }

    /**
     *
     * 清空聊天记录
     * @return \support\Response
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function cleanChatPost()
    {
        $id = input('id', null);
        $data = BotService::getBot($id);

        if (!$data) {
            return $this->error('参数错误');
        }

        $client = BotService::getRobotClient($data);
        $res = $client->cleanChatHistory([
            'robot_wxid' => $data['uin'],
            'uuid' => $data['uuid']
        ]);
        if($res['code']){
            return $this->success('操作成功');
        }
        return $this->error('操作失败：' . $res['errmsg']);
    }
}